From 93e59bf1473739c713935b501ffbd3ea3f366ab8 Mon Sep 17 00:00:00 2001 From: Jimi Xenidis Date: Sun, 8 Oct 2006 11:34:24 -0400 Subject: [PATCH] [XEN][POWERPC] Create a Domain Foreign Map space The following patch creates a Domain Foreign Map space that is uses to map granted memory into the Linear Map of the domain. The Linear Map of Linux is the is the Kernel Virtual address space where VA = PA + PAGE_OFFSET. Also: - lots of grant_* interfaces work now - mm.[ch] cleanups - first pass at extracting Page Table operations from PAPR interfaces - get_page_type() fix logic bug - recognize a grant table mapping by placing its gmfn at the end of real memory. - grant table usually mapped like an IO page, so force WIMG bits I=0 - mfn_to_gmfn and pfn2mfn get WAY to complex, need get a simpler model in. - communicate the Domain Foreign Map to domains using /xen/foreign-map - make sure all bit definitions are UL where possible - now that we actually assign Xen heap pages to domains they must be relinquished Signed-off-by: Jimi Xenidis Signed-off-by: Hollis Blanchard --- xen/arch/powerpc/domain.c | 2 + xen/arch/powerpc/mm.c | 164 ++++++++++++++++++++++---- xen/arch/powerpc/ofd_fixup.c | 5 + xen/arch/powerpc/papr/xlate.c | 116 ++++++++++-------- xen/include/asm-powerpc/grant_table.h | 16 ++- xen/include/asm-powerpc/mm.h | 76 +++++++++--- 6 files changed, 291 insertions(+), 88 deletions(-) diff --git a/xen/arch/powerpc/domain.c b/xen/arch/powerpc/domain.c index 7d69f72fe9..f2fe28048c 100644 --- a/xen/arch/powerpc/domain.c +++ b/xen/arch/powerpc/domain.c @@ -94,6 +94,7 @@ int arch_domain_create(struct domain *d) void arch_domain_destroy(struct domain *d) { shadow_teardown(d); + /* shared_info is part of the RMA so no need to release it */ } static void machine_fail(const char *s) @@ -290,6 +291,7 @@ static void relinquish_memory(struct domain *d, struct list_head *list) void domain_relinquish_resources(struct domain *d) { + relinquish_memory(d, &d->xenpage_list); relinquish_memory(d, &d->page_list); free_extents(d); return; diff --git a/xen/arch/powerpc/mm.c b/xen/arch/powerpc/mm.c index 06341511da..7d38872d7d 100644 --- a/xen/arch/powerpc/mm.c +++ b/xen/arch/powerpc/mm.c @@ -41,18 +41,107 @@ struct page_info *frame_table; unsigned long max_page; unsigned long total_pages; +void __init init_frametable(void) +{ + unsigned long p; + unsigned long nr_pages; + int i; + + nr_pages = PFN_UP(max_page * sizeof(struct page_info)); + + p = alloc_boot_pages(nr_pages, 1); + if (p == 0) + panic("Not enough memory for frame table\n"); + + frame_table = (struct page_info *)(p << PAGE_SHIFT); + for (i = 0; i < nr_pages; i += 1) + clear_page((void *)((p + i) << PAGE_SHIFT)); +} + +void share_xen_page_with_guest( + struct page_info *page, struct domain *d, int readonly) +{ + if ( page_get_owner(page) == d ) + return; + + /* this causes us to leak pages in the Domain and reuslts in + * Zombie domains, I think we are missing a piece, until we find + * it we disable the following code */ + set_gpfn_from_mfn(page_to_mfn(page), INVALID_M2P_ENTRY); + + spin_lock(&d->page_alloc_lock); + + /* The incremented type count pins as writable or read-only. */ + page->u.inuse.type_info = (readonly ? PGT_none : PGT_writable_page); + page->u.inuse.type_info |= PGT_validated | 1; + + page_set_owner(page, d); + wmb(); /* install valid domain ptr before updating refcnt. */ + ASSERT(page->count_info == 0); + page->count_info |= PGC_allocated | 1; + + if ( unlikely(d->xenheap_pages++ == 0) ) + get_knownalive_domain(d); + list_add_tail(&page->list, &d->xenpage_list); + + spin_unlock(&d->page_alloc_lock); +} + +void share_xen_page_with_privileged_guests( + struct page_info *page, int readonly) +{ + unimplemented(); +} + +static int create_grant_va_mapping( + unsigned long va, unsigned long frame, struct vcpu *v) +{ + if (v->domain->domain_id != 0) { + printk("only Dom0 can map a grant entry\n"); + BUG(); + return GNTST_permission_denied; + } + return GNTST_okay; +} + +static int destroy_grant_va_mapping( + unsigned long addr, unsigned long frame, struct domain *d) +{ + if (d->domain_id != 0) { + printk("only Dom0 can map a grant entry\n"); + BUG(); + return GNTST_permission_denied; + } + return GNTST_okay; +} + int create_grant_host_mapping( unsigned long addr, unsigned long frame, unsigned int flags) { - panic("%s called\n", __func__); - return 1; + if (flags & GNTMAP_application_map) { + printk("%s: GNTMAP_application_map not supported\n", __func__); + BUG(); + return GNTST_general_error; + } + if (flags & GNTMAP_contains_pte) { + printk("%s: GNTMAP_contains_pte not supported\n", __func__); + BUG(); + return GNTST_general_error; + } + return create_grant_va_mapping(addr, frame, current); } int destroy_grant_host_mapping( unsigned long addr, unsigned long frame, unsigned int flags) { - panic("%s called\n", __func__); - return 1; + if (flags & GNTMAP_contains_pte) { + printk("%s: GNTMAP_contains_pte not supported\n", __func__); + BUG(); + return GNTST_general_error; + } + + /* may have force the remove here */ + return destroy_grant_va_mapping(addr, frame, current->domain); } int steal_page(struct domain *d, struct page_info *page, unsigned int memflags) @@ -138,7 +227,7 @@ int get_page_type(struct page_info *page, unsigned long type) { return 0; } - if ( unlikely(!(x & PGT_validated)) ) + else if ( unlikely(!(x & PGT_validated)) ) { /* Someone else is updating validation of this page. Wait... */ while ( (y = page->u.inuse.type_info) == x ) @@ -157,23 +246,6 @@ int get_page_type(struct page_info *page, unsigned long type) return 1; } -void __init init_frametable(void) -{ - unsigned long p; - unsigned long nr_pages; - int i; - - nr_pages = PFN_UP(max_page * sizeof(struct page_info)); - - p = alloc_boot_pages(nr_pages, 1); - if (p == 0) - panic("Not enough memory for frame table\n"); - - frame_table = (struct page_info *)(p << PAGE_SHIFT); - for (i = 0; i < nr_pages; i += 1) - clear_page((void *)((p + i) << PAGE_SHIFT)); -} - long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) { printk("%s: no PPC specific memory ops\n", __func__); @@ -311,9 +383,18 @@ ulong pfn2mfn(struct domain *d, ulong pfn, int *type) struct page_extents *pe; ulong mfn = INVALID_MFN; int t = PFN_TYPE_NONE; + ulong foreign_map_pfn = 1UL << cpu_foreign_map_order(); /* quick tests first */ - if (d->is_privileged && cpu_io_mfn(pfn)) { + if (pfn & foreign_map_pfn) { + t = PFN_TYPE_FOREIGN; + mfn = pfn & ~(foreign_map_pfn); + } else if (pfn >= max_page && pfn < (max_page + NR_GRANT_FRAMES)) { + /* Its a grant table access */ + t = PFN_TYPE_GNTTAB; + mfn = gnttab_shared_mfn(d, d->grant_table, (pfn - max_page)); + } else if (test_bit(_DOMF_privileged, &d->domain_flags) && + cpu_io_mfn(pfn)) { t = PFN_TYPE_IO; mfn = pfn; } else { @@ -365,6 +446,43 @@ ulong pfn2mfn(struct domain *d, ulong pfn, int *type) return mfn; } +unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn) +{ + struct page_extents *pe; + ulong cur_pfn; + ulong gnttab_mfn; + ulong rma_mfn; + + /* grant? */ + gnttab_mfn = gnttab_shared_mfn(d, d->grant_table, 0); + if (mfn >= gnttab_mfn && mfn < (gnttab_mfn + NR_GRANT_FRAMES)) + return max_page + (mfn - gnttab_mfn); + + /* IO? */ + if (test_bit(_DOMF_privileged, &d->domain_flags) && + cpu_io_mfn(mfn)) + return mfn; + + rma_mfn = page_to_mfn(d->arch.rma_page); + if (mfn >= rma_mfn && + mfn < (rma_mfn + (1 << d->arch.rma_order))) + return mfn - rma_mfn; + + /* Extent? */ + cur_pfn = 1UL << d->arch.rma_order; + list_for_each_entry (pe, &d->arch.extent_list, pe_list) { + uint pe_pages = 1UL << pe->order; + uint b_mfn = page_to_mfn(pe->pg); + uint e_mfn = b_mfn + pe_pages; + + if (mfn >= b_mfn && mfn < e_mfn) { + return cur_pfn + (mfn - b_mfn); + } + cur_pfn += pe_pages; + } + return INVALID_M2P_ENTRY; +} + void guest_physmap_add_page( struct domain *d, unsigned long gpfn, unsigned long mfn) { diff --git a/xen/arch/powerpc/ofd_fixup.c b/xen/arch/powerpc/ofd_fixup.c index 9ed61c012b..816fd19189 100644 --- a/xen/arch/powerpc/ofd_fixup.c +++ b/xen/arch/powerpc/ofd_fixup.c @@ -352,6 +352,11 @@ static ofdn_t ofd_xen_props(void *m, struct domain *d, start_info_t *si) if (!rtas_entry) ofd_prop_add(m, n, "power-control", NULL, 0); + /* tell dom0 where ranted pages go in the linear map */ + val[0] = cpu_foreign_map_order(); + val[1] = max_page; + ofd_prop_add(m, n, "foreign-map", val, sizeof (val)); + n = ofd_node_add(m, n, console, sizeof (console)); if (n > 0) { val[0] = 0; diff --git a/xen/arch/powerpc/papr/xlate.c b/xen/arch/powerpc/papr/xlate.c index bfc3af9031..1a08215df8 100644 --- a/xen/arch/powerpc/papr/xlate.c +++ b/xen/arch/powerpc/papr/xlate.c @@ -117,11 +117,8 @@ static void pte_tlbie(union pte volatile *pte, ulong ptex) } -static void h_enter(struct cpu_user_regs *regs) +long pte_enter(ulong flags, ulong ptex, ulong vsid, ulong rpn) { - ulong flags = regs->gprs[4]; - ulong ptex = regs->gprs[5]; - union pte pte; union pte volatile *ppte; struct domain_htab *htab; @@ -141,13 +138,12 @@ static void h_enter(struct cpu_user_regs *regs) htab = &d->arch.htab; if (ptex > (1UL << htab->log_num_ptes)) { DBG("%s: bad ptex: 0x%lx\n", __func__, ptex); - regs->gprs[3] = H_Parameter; - return; + return H_Parameter; } /* use local HPTE to avoid manual shifting & masking */ - pte.words.vsid = regs->gprs[6]; - pte.words.rpn = regs->gprs[7]; + pte.words.vsid = vsid; + pte.words.rpn = rpn; if ( pte.bits.l ) { /* large page? */ /* figure out the page size for the selected large page */ @@ -163,8 +159,7 @@ static void h_enter(struct cpu_user_regs *regs) if ( lp_size >= d->arch.large_page_sizes ) { DBG("%s: attempt to use unsupported lp_size %d\n", __func__, lp_size); - regs->gprs[3] = H_Parameter; - return; + return H_Parameter; } /* get correct pgshift value */ @@ -180,19 +175,16 @@ static void h_enter(struct cpu_user_regs *regs) mfn = pfn2mfn(d, pfn, &mtype); if (mfn == INVALID_MFN) { DBG("%s: Bad PFN: 0x%lx\n", __func__, pfn); - regs->gprs[3] = H_Parameter; - return; + return H_Parameter; } - if (mtype == PFN_TYPE_IO) { + if (mtype == PFN_TYPE_IO &&!test_bit(_DOMF_privileged, &d->domain_flags)) { /* only a privilaged dom can access outside IO space */ - if ( !d->is_privileged ) { - DBG("%s: unprivileged access to physical page: 0x%lx\n", - __func__, pfn); - regs->gprs[3] = H_Privilege; - return; - } - + DBG("%s: unprivileged access to physical page: 0x%lx\n", + __func__, pfn); + return H_Privilege; + } + if (mtype == PFN_TYPE_IO) { if ( !((pte.bits.w == 0) && (pte.bits.i == 1) && (pte.bits.g == 1)) ) { @@ -200,10 +192,14 @@ static void h_enter(struct cpu_user_regs *regs) "w=%x i=%d m=%d, g=%d\n word 0x%lx\n", __func__, pte.bits.w, pte.bits.i, pte.bits.m, pte.bits.g, pte.words.rpn); - regs->gprs[3] = H_Parameter; - return; + return H_Parameter; } } + if (mtype == PFN_TYPE_GNTTAB) { + DBG("%s: Dom[%d] mapping grant table: 0x%lx\n", + __func__, d->domain_id, pfn << PAGE_SHIFT); + pte.bits.i = 0; + } /* fixup the RPN field of our local PTE copy */ pte.bits.rpn = mfn | lp_bits; @@ -224,14 +220,12 @@ static void h_enter(struct cpu_user_regs *regs) if (unlikely(!get_domain(f))) { DBG("%s: Rescinded, no domain: 0x%lx\n", __func__, pfn); - regs->gprs[3] = H_Rescinded; - return; + return H_Rescinded; } if (unlikely(!get_page(pg, f))) { put_domain(f); DBG("%s: Rescinded, no page: 0x%lx\n", __func__, pfn); - regs->gprs[3] = H_Rescinded; - return; + return H_Rescinded; } } @@ -288,10 +282,7 @@ static void h_enter(struct cpu_user_regs *regs) : "b" (ppte), "r" (pte.words.rpn), "r" (pte.words.vsid) : "memory"); - regs->gprs[3] = H_Success; - regs->gprs[4] = idx; - - return; + return idx; } } @@ -304,7 +295,24 @@ static void h_enter(struct cpu_user_regs *regs) if (f != NULL) put_domain(f); - regs->gprs[3] = H_PTEG_Full; + return H_PTEG_Full; +} + +static void h_enter(struct cpu_user_regs *regs) +{ + ulong flags = regs->gprs[4]; + ulong ptex = regs->gprs[5]; + ulong vsid = regs->gprs[6]; + ulong rpn = regs->gprs[7]; + long ret; + + ret = pte_enter(flags, ptex, vsid, rpn); + + if (ret >= 0) { + regs->gprs[3] = H_Success; + regs->gprs[4] = ret; + } else + regs->gprs[3] = ret; } static void h_protect(struct cpu_user_regs *regs) @@ -332,7 +340,7 @@ static void h_protect(struct cpu_user_regs *regs) /* the AVPN param occupies the bit-space of the word */ if ( (flags & H_AVPN) && lpte.bits.avpn != avpn >> 7 ) { - DBG("%s: %p: AVPN check failed: 0x%lx, 0x%lx\n", __func__, + DBG_LOW("%s: %p: AVPN check failed: 0x%lx, 0x%lx\n", __func__, ppte, lpte.words.vsid, lpte.words.rpn); regs->gprs[3] = H_Not_Found; return; @@ -469,11 +477,8 @@ static void h_clear_mod(struct cpu_user_regs *regs) } } -static void h_remove(struct cpu_user_regs *regs) +long pte_remove(ulong flags, ulong ptex, ulong avpn, ulong *hi, ulong *lo) { - ulong flags = regs->gprs[4]; - ulong ptex = regs->gprs[5]; - ulong avpn = regs->gprs[6]; struct vcpu *v = get_current(); struct domain *d = v->domain; struct domain_htab *htab = &d->arch.htab; @@ -485,29 +490,25 @@ static void h_remove(struct cpu_user_regs *regs) if ( ptex > (1UL << htab->log_num_ptes) ) { DBG("%s: bad ptex: 0x%lx\n", __func__, ptex); - regs->gprs[3] = H_Parameter; - return; + return H_Parameter; } pte = &htab->map[ptex]; lpte.words.vsid = pte->words.vsid; lpte.words.rpn = pte->words.rpn; if ((flags & H_AVPN) && lpte.bits.avpn != (avpn >> 7)) { - DBG("%s: avpn doesn not match\n", __func__); - regs->gprs[3] = H_Not_Found; - return; + DBG_LOW("%s: AVPN does not match\n", __func__); + return H_Not_Found; } if ((flags & H_ANDCOND) && ((avpn & pte->words.vsid) != 0)) { DBG("%s: andcond does not match\n", __func__); - regs->gprs[3] = H_Not_Found; - return; + return H_Not_Found; } - regs->gprs[3] = H_Success; /* return old PTE in regs 4 and 5 */ - regs->gprs[4] = lpte.words.vsid; - regs->gprs[5] = lpte.words.rpn; + *hi = lpte.words.vsid; + *lo = lpte.words.rpn; #ifdef DEBUG_LOW /* XXX - I'm very skeptical of doing ANYTHING if not bits.v */ @@ -522,7 +523,7 @@ static void h_remove(struct cpu_user_regs *regs) if (!cpu_io_mfn(mfn)) { struct page_info *pg = mfn_to_page(mfn); struct domain *f = page_get_owner(pg); - + if (f != d) { put_domain(f); put_page(pg); @@ -536,6 +537,27 @@ static void h_remove(struct cpu_user_regs *regs) : "memory"); pte_tlbie(&lpte, ptex); + + return H_Success; +} + +static void h_remove(struct cpu_user_regs *regs) +{ + ulong flags = regs->gprs[4]; + ulong ptex = regs->gprs[5]; + ulong avpn = regs->gprs[6]; + ulong hi, lo; + long ret; + + ret = pte_remove(flags, ptex, avpn, &hi, &lo); + + regs->gprs[3] = ret; + + if (ret == H_Success) { + regs->gprs[4] = hi; + regs->gprs[5] = lo; + } + return; } static void h_read(struct cpu_user_regs *regs) diff --git a/xen/include/asm-powerpc/grant_table.h b/xen/include/asm-powerpc/grant_table.h index e573f714a2..32920dad0a 100644 --- a/xen/include/asm-powerpc/grant_table.h +++ b/xen/include/asm-powerpc/grant_table.h @@ -29,6 +29,10 @@ * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and * must hold a reference to the page. */ +extern long pte_enter(ulong flags, ulong ptex, ulong vsid, ulong rpn); +extern long pte_remove(ulong flags, ulong ptex, ulong avpn, + ulong *hi, ulong *lo); + int create_grant_host_mapping( unsigned long addr, unsigned long frame, unsigned int flags); int destroy_grant_host_mapping( @@ -41,8 +45,7 @@ int destroy_grant_host_mapping( (d), XENSHARE_writable); \ } while ( 0 ) -#define gnttab_shared_mfn(d, t, i) \ - ((virt_to_maddr((t)->shared) >> PAGE_SHIFT) + (i)) +#define gnttab_shared_mfn(d, t, i) (((ulong)((t)->shared) >> PAGE_SHIFT) + (i)) #define gnttab_shared_gmfn(d, t, i) \ (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i))) @@ -61,4 +64,13 @@ static inline void gnttab_clear_flag(unsigned long nr, uint16_t *addr) clear_bit(lnr, laddr); } +static inline uint cpu_foreign_map_order(void) +{ + /* 16 GiB */ + return 34 - PAGE_SHIFT; +} + +#define GNTTAB_DEV_BUS(f) \ + ((f) | (1UL << (cpu_foreign_map_order() + PAGE_SHIFT))) + #endif /* __ASM_PPC_GRANT_TABLE_H__ */ diff --git a/xen/include/asm-powerpc/mm.h b/xen/include/asm-powerpc/mm.h index 89306a3c95..78886bcc38 100644 --- a/xen/include/asm-powerpc/mm.h +++ b/xen/include/asm-powerpc/mm.h @@ -13,9 +13,10 @@ * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Copyright (C) IBM Corp. 2005 + * Copyright (C) IBM Corp. 2005, 2006 * * Authors: Hollis Blanchard + * Jimi Xenidis */ #ifndef _ASM_MM_H_ @@ -90,35 +91,35 @@ struct page_extents { }; /* The following page types are MUTUALLY EXCLUSIVE. */ -#define PGT_none (0<<29) /* no special uses of this page */ -#define PGT_RMA (1<<29) /* This page is an RMA page? */ -#define PGT_writable_page (7<<29) /* has writable mappings of this page? */ -#define PGT_type_mask (7<<29) /* Bits 29-31. */ +#define PGT_none (0UL<<29) /* no special uses of this page */ +#define PGT_RMA (1UL<<29) /* This page is an RMA page? */ +#define PGT_writable_page (7UL<<29) /* has writable mappings of this page? */ +#define PGT_type_mask (7UL<<29) /* Bits 29-31. */ /* Owning guest has pinned this page to its current type? */ #define _PGT_pinned 28 -#define PGT_pinned (1U<<_PGT_pinned) +#define PGT_pinned (1UL<<_PGT_pinned) /* Has this page been validated for use as its current type? */ #define _PGT_validated 27 -#define PGT_validated (1U<<_PGT_validated) +#define PGT_validated (1UL<<_PGT_validated) /* 16-bit count of uses of this frame as its current type. */ -#define PGT_count_mask ((1U<<16)-1) +#define PGT_count_mask ((1UL<<16)-1) /* Cleared when the owning guest 'frees' this page. */ #define _PGC_allocated 31 -#define PGC_allocated (1U<<_PGC_allocated) +#define PGC_allocated (1UL<<_PGC_allocated) /* Set on a *guest* page to mark it out-of-sync with its shadow */ #define _PGC_out_of_sync 30 -#define PGC_out_of_sync (1U<<_PGC_out_of_sync) +#define PGC_out_of_sync (1UL<<_PGC_out_of_sync) /* Set when is using a page as a page table */ #define _PGC_page_table 29 -#define PGC_page_table (1U<<_PGC_page_table) +#define PGC_page_table (1UL<<_PGC_page_table) /* Set when using page for RMA */ #define _PGC_page_RMA 28 -#define PGC_page_RMA (1U<<_PGC_page_RMA) +#define PGC_page_RMA (1UL<<_PGC_page_RMA) /* 29-bit count of references to this frame. */ -#define PGC_count_mask ((1U<<28)-1) +#define PGC_count_mask ((1UL<<28)-1) #define IS_XEN_HEAP_FRAME(_pfn) (page_to_maddr(_pfn) < xenheap_phys_end) @@ -133,6 +134,13 @@ static inline u32 pickle_domptr(struct domain *domain) #define page_get_owner(_p) (unpickle_domptr((_p)->u.inuse._domain)) #define page_set_owner(_p,_d) ((_p)->u.inuse._domain = pickle_domptr(_d)) +#define XENSHARE_writable 0 +#define XENSHARE_readonly 1 +extern void share_xen_page_with_guest( + struct page_info *page, struct domain *d, int readonly); +extern void share_xen_page_with_privileged_guests( + struct page_info *page, int readonly); + extern struct page_info *frame_table; extern unsigned long max_page; extern unsigned long total_pages; @@ -218,11 +226,47 @@ typedef struct { } vm_assist_info_t; extern vm_assist_info_t vm_assist_info[]; -#define share_xen_page_with_guest(p, d, r) do { } while (0) -#define share_xen_page_with_privileged_guests(p, r) do { } while (0) /* hope that accesses to this will fail spectacularly */ -#define machine_to_phys_mapping ((u32 *)-1UL) +#undef machine_to_phys_mapping +#define INVALID_M2P_ENTRY (~0UL) + +/* do nothing, its all calculated */ +#define set_gpfn_from_mfn(mfn, pfn) do { } while (0) +#define get_gpfn_from_mfn(mfn) (mfn) + +extern unsigned long mfn_to_gmfn(struct domain *d, unsigned long mfn); + +extern unsigned long paddr_to_maddr(unsigned long paddr); + +#define INVALID_MFN (~0UL) +#define PFN_TYPE_NONE 0 +#define PFN_TYPE_RMA 1 +#define PFN_TYPE_LOGICAL 2 +#define PFN_TYPE_IO 3 +#define PFN_TYPE_FOREIGN 4 +#define PFN_TYPE_GNTTAB 5 + +extern ulong pfn2mfn(struct domain *d, ulong pfn, int *type); +static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gmfn) +{ + int mtype; + ulong mfn; + + mfn = pfn2mfn(d, gmfn, &mtype); + if (mfn != INVALID_MFN) { + switch (mtype) { + case PFN_TYPE_RMA: + case PFN_TYPE_LOGICAL: + break; + default: + WARN(); + mfn = INVALID_MFN; + break; + } + } + return mfn; +} extern int update_grant_va_mapping(unsigned long va, unsigned long val, -- 2.30.2